1 module hip.math.utils;
2 import hip.math.vector;
3 
4 ///There are some errors occurring when compiling with LDC
5 public import core.math: sqrt, cos, sin;
6 
7 pure @safe nothrow @nogc:
8 
9 enum PI = 3.14159;
10 enum PI_2 = PI/2;
11 enum PI_4 = PI/4;
12 
13 enum RAD_TO_DEG = 180/PI;
14 enum DEG_TO_RAD = PI/180;
15 
16 float radToDeg(float radians)
17 {
18     assert(radians == radians); //float.nan check
19     return radians*RAD_TO_DEG;
20 }
21 float degToRad(float degrees)
22 {
23     assert(degrees == degrees); //float.nan check
24     return DEG_TO_RAD * degrees;
25 }
26 
27 int getClosestMultiple(int from, int to)
28 {
29     float temp = to/cast(float)from;
30     int tempI = to/from;
31 
32     if(temp == tempI)
33         return from * tempI;
34     else
35     {
36         temp-= tempI;
37         if(temp <= 0.5)
38             return from*tempI;
39         else
40             return from*(tempI+1);
41     }
42 }
43 
44 bool approximatelyEqual(in float from, in float to, in float error = 0.01)
45 {
46     float diff = from - to;
47     return diff >= -error && diff <= error;
48 }
49 
50 pragma(inline, true) int round(float f) pure @nogc @safe nothrow {return f > 0 ? cast(int)(f+0.5) : cast(int)(f-0.5);}
51 
52 ///Bit twiddling hacks
53 uint roundPow2(uint n)
54 {
55     if(n == 0) return 1;
56     n--;
57     n |= n >> 1;
58     n |= n >> 2;
59     n |= n >> 4;
60     n |= n >> 8;
61     n |= n >> 16;
62     return n + 1;
63 }
64 
65 /** 
66  * 
67  * Params:
68  *   from = From which value to interpolate
69  *   to = To which value
70  *   t = The T of interpolation
71  * Returns: 
72  */
73 float lerp(float from, float to, float t)
74 {
75     return (1.0f-t)*from + t*to;
76 }
77 
78 bool isPowerOf2(size_t num)
79 {
80     return (num & (num - 1)) == 0;
81 }
82 
83 enum dipsPerInch = 96.0f;
84 int convertDipsToPixels(float dips, float dpi = 96.0f) //96 is Windows convention
85 {
86     return cast(int)(dips * dpi / dipsPerInch + 0.5f); //Round to nearest integer
87 }
88 
89 float physicalPixelToDIPs(int pixels, float dpi = 96.0f)
90 {
91     return pixels/(dpi/dipsPerInch);
92 }
93 
94 enum AxisNavigation{xy, yz, xz, zx, zy, yx}
95 
96 Vector3 toCircleBounds(Vector3 v, float angle, AxisNavigation axis=AxisNavigation.xy)
97 {
98     float mag = v.mag;
99     final switch(axis) with(AxisNavigation)
100     {
101         case xy:
102             v.x = cos(angle)*mag;
103             v.y = sin(angle)*mag;
104             break;
105         case yz:
106             v.y = cos(angle)*mag;
107             v.z = sin(angle)*mag;
108             break;
109         case xz:
110             v.x = cos(angle)*mag;
111             v.z = sin(angle)*mag;
112             break;
113         case zx:
114             v.z = cos(angle)*mag;
115             v.x = sin(angle)*mag;
116             break;
117         case zy:
118             v.z = cos(angle)*mag;
119             v.y = sin(angle)*mag;
120             break;
121         case yx:
122             v.y = cos(angle)*mag;
123             v.x = sin(angle)*mag;
124             break;
125     }
126     return v;
127 }
128 
129 pragma(inline, true)
130 T abs(T)(T val) pure nothrow @safe @nogc
131 {
132     return val < 0 ? -val : val;
133 }
134 
135 T min(T)(in T[] values ...) pure nothrow @safe @nogc
136 {
137     T v = values[0];
138     for(int i = 1; i < values.length; i++)
139         if(values[i] < v)
140             v = values[i];
141     return v;
142 }
143 
144 T max(T)(in T[] values ...) pure nothrow @safe @nogc
145 {
146     T v = values[0];
147     for(int i = 1; i < values.length; i++)
148         if(values[i] > v)
149             v = values[i];
150     return v;
151 }
152 
153 T sum(T)(in T[] values ...) pure nothrow @safe @nogc
154 {
155     T sum = 0;
156     foreach(v; values) sum+= v;
157     return sum;
158 }
159 
160 
161 float floor(in float val) pure nothrow @safe @nogc{return floor!float(val);}
162 T floor(T)(in float val) pure nothrow @safe @nogc
163 {
164     return cast(T)(cast(int)val);
165 }
166 float ceil(in float val) pure nothrow @safe @nogc {return ceil!float(val);}
167 T ceil(T)(in float val) pure nothrow @safe @nogc
168 {
169     return cast(T)(cast(int)(val + 0.9999999));
170 }
171 
172 
173 T clamp(T)(T value, T min, T max) pure nothrow @safe @nogc
174 {
175     return value < min ? min : value > max ? max : value;
176 }
177 
178 pragma(inline)T abs(T)(in T value){return value < 0 ? -value : value;}
179 
180 int greatestCommonDivisor(int a, int b)
181 {
182     int res;
183     int lastRes;
184     do
185     {
186         res = a % b;
187         lastRes = b;
188         a = b;
189         b = res;
190     } while(res != 0);
191 
192     return lastRes;
193 }
194 
195 Vector2 quadraticBezier(float x0, float y0, float x1, float y1, float x2, float y2, float t)
196 {
197     float dtT = (1.0f-t);
198     float dtTSquare = dtT*dtT;
199     float tSq = t*t;
200     return Vector2(
201         dtTSquare*x0 + 2*t*dtT*x1 + tSq*x2, 
202         dtTSquare*y0 + 2*t*dtT*y1 + tSq*y2
203     );
204 }
205 
206 pragma(inline) Vector2 quadraticBezier(Vector2 p0, Vector2 p1, Vector2 p2, float t)
207 {
208     return quadraticBezier(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, t);
209 }
210 
211 Vector2 cubicBezier(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float t)
212 {
213     float dtT = 1.0f-t;
214     float dtTSq = dtT*dtT;
215     float dtTCub = dtTSq*dtT;
216     float tSq = t*t;
217     float tCub = tSq*t;
218 
219     return Vector2(
220         dtTCub*x0 + 3*t*dtTSq*x1 + 3*tSq*dtT*x2 + tCub*x3,
221         dtTCub*y0 + 3*t*dtTSq*y1 + 3*tSq*dtT*y2 + tCub*y3,
222     );
223 }
224 
225 pragma(inline) Vector2 cubicBezier(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
226 {
227     return cubicBezier(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, t);
228 }